/*
 * Copyright (C) 2010-2011 Comcast Cable.  All Rights Reserved.
 */
package com.hercules.android.receiver.handlers.commands;

import com.hercules.android.receiver.AndroidReceiver;
import com.hercules.android.receiver.LogUtil;
import com.hercules.android.receiver.handlers.commands.CommandHandlersUtil.ValidationException;
import com.hercules.android.receiver.handlers.events.EventListenerBinder;
import com.hercules.android.receiver.model.commands.XRECommand;
import com.hercules.android.receiver.model.commands.XRENewCommand;
import com.hercules.android.receiver.model.objects.XREAbsoluteScaleAnimation;
import com.hercules.android.receiver.model.objects.XREAbsoluteTranslationAnimation;
import com.hercules.android.receiver.model.objects.XREAlphaAnimation;
import com.hercules.android.receiver.model.objects.XREAnimationEasingFunction;
import com.hercules.android.receiver.model.objects.XREAnimationResource;
import com.hercules.android.receiver.model.objects.XREApplication;
import com.hercules.android.receiver.model.objects.XRECommandSequence;
import com.hercules.android.receiver.model.objects.XREDimensionsAnimation;
import com.hercules.android.receiver.model.objects.DoNothingSound;
import com.hercules.android.receiver.model.objects.XREFlash;
import com.hercules.android.receiver.model.objects.XREFont;
import com.hercules.android.receiver.model.objects.XREHTMLText;
import com.hercules.android.receiver.model.objects.XREHTMLView;
import com.hercules.android.receiver.model.objects.XREImage;
import com.hercules.android.receiver.model.objects.XREImageQuality;
import com.hercules.android.receiver.model.objects.XRENineSliceImage;
import com.hercules.android.receiver.model.objects.XREObject;
import com.hercules.android.receiver.model.objects.XRERectangle;
import com.hercules.android.receiver.model.objects.XREResource;
import com.hercules.android.receiver.model.objects.XREResourceOptions;
import com.hercules.android.receiver.model.objects.XREServiceProxy;
import com.hercules.android.receiver.model.objects.XRESound;
import com.hercules.android.receiver.model.objects.XREStylesheet;
import com.hercules.android.receiver.model.objects.XREText;
import com.hercules.android.receiver.model.objects.XRETextInput;
import com.hercules.android.receiver.model.objects.XRETransformAnimation;
import com.hercules.android.receiver.model.objects.XREVideo;
import com.hercules.android.receiver.model.objects.XREView;
import com.hercules.android.receiver.painting.PaintersUtil;
import com.hercules.android.receiver.painting.XREObjectPainterException;
import com.hercules.android.receiver.painting.resources.XRESoundUtil;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

/**
 * The handler used to process XRENewCommand. It will create the new XREObject and paint affected views. It extends
 * XREObjectCommandHandler for convenience.
 * <p>
 * <b>Sample Usage:</b> Please look at sample usage of {@link XREAggregateCommandHandler}.
 * <p>
 * <b>Thread Safety:</b> This class is not thread safe since it has mutable fields. But if they are not changed after
 * first configured, then this class is used in a thread safe manner.
 *
 * @author liuliquan, 7realm
 * @author 7realm
 * @version 1.0
 */
@SuppressWarnings("unchecked")
public class XRENewCommandHandler extends XREObjectCommandHandler {
    /** Represents supported font styles. */
    private static final Set<String> FONT_STYLES =
        new HashSet<String>(Arrays.asList(XREFont.STYLE_BOLD, XREFont.STYLE_BOLDITALIC, XREFont.STYLE_ITALIC,
            XREFont.STYLE_NORMAL));

    /**
     * Represents XREView event binder. It used to bind XREView events (OnKeyUp, OnMouseUp, ...) to UI views.
     * <p>
     * Can be any value, has getter and setter. Is used in processCommandMessage method.
     * <p>
     * AndroidAssembly1 new field, together with getter and setter
     */
    private EventListenerBinder binder;

    /**
     * Default empty constructor.
     */
    public XRENewCommandHandler() {
        // empty
    }

    /**
     * Gets the XREView event binder.
     *
     * @return the xREView event binder
     */
    public EventListenerBinder getBinder() {
        return binder;
    }

    /**
     * Sets the XREView event binder.
     *
     * @param binder the xREView event binder
     */
    public void setBinder(EventListenerBinder binder) {
        this.binder = binder;
    }

    /**
     * Handle given NEW command message. The affected view will be painted.
     *
     * @param command the XRE NEW command to be handled
     * @param receiver the receiver for the XRE application
     * @throws IllegalArgumentException if given command or receiver is null
     * @throws IllegalStateException if required property is not set
     * @throws XREObjectCreationException if error occurs while creating the XREObject
     * @throws InvalidXRECommandParameterException if any command parameter has invalid value
     * @throws UnsupportedXRECommandParameterException if any command parameter is not supported
     * @throws DuplicateXREObjectIdException if the XREObject to be created has a duplicate ID which already exists
     * @throws XREObjectNotFoundException if any XREObject to be associated is not found
     * @throws XREViewFinderUtilityException if any error occurs while finding the affected views
     * @throws XREObjectCommandHandlerException if any other error occurs while handling the command
     */
    @SuppressWarnings("boxing")
    @Override
    protected void processCommandMessage(XRECommand command, AndroidReceiver receiver)
        throws XREObjectCommandHandlerException {
        String methodName = "processCommandMessage";
        LogUtil.enter(getLogger(), this, methodName, command, receiver);

        try {
            // check state binder
            CommandHandlersUtil.checkState(binder, "binder");

            // check arguments
            XRENewCommand newCommand = CommandHandlersUtil.checkCommand(command, XRENewCommand.class);
            CommandHandlersUtil.checkReceiver(receiver);

            // call pre painting handler
            callPrePaintHandler(receiver, newCommand);

            Map<Integer, XREObject> elementsMap = receiver.getApplicationData().getElementsXREIdToObject();

            // create object by given class
            XREObject xreObject = createObject(newCommand.getKlass());
            int id = newCommand.getId();
            if (id < XREObject.ID_CLIENT) {
                throw new InvalidXRECommandParameterException("ID of created object is less than first ID, "
                    + "that can be used (XREObject.ID_CLIENT = " + XREObject.ID_CLIENT + ").", "id", id);
            }
            if (elementsMap.containsKey(id)) {
                throw new DuplicateXREObjectIdException("ID - {0} of created object already exists.", id);
            }
            xreObject.setId(id);

            // check and copy command parameters
            if (newCommand.getParams() == null) {
                throw new InvalidXRECommandParameterException("Command 'params' property is null.", "params", null);
            }

            // make shallow copy
            Map<String, Object> params = new TreeMap<String, Object>(newCommand.getParams());

            // add created object to ApplicationData
            elementsMap.put(id, xreObject);
            
            populate(receiver, newCommand, elementsMap, xreObject, params);

            // check if all parameters were processed
            CommandHandlersUtil.checkParams(params, "params", getLogger(), this, methodName);


            // use affectedViewFinder utility to find affected views
            List<XREView> affectedViews = getAffectedViewFinder().getAffectedViews(newCommand, receiver);

            // paint affect views
            paintAffectedViews(affectedViews, newCommand, receiver);
            
            // setup event handlers
            CommandHandlersUtil.setupHandlers(getLogger(), this, methodName, xreObject, params, elementsMap, receiver,
                binder);
            
            LogUtil.exit(getLogger(), this, methodName);
        } catch (IllegalArgumentException e) {
            throw LogUtil.error(getLogger(), this, methodName, e);
        } catch (XREObjectCommandHandlerException e) {
            throw LogUtil.error(getLogger(), this, methodName, e);
        } catch (ValidationException e) {
            throw LogUtil.error(getLogger(), this, methodName, new XREObjectCommandHandlerException(e.getMessage(), e));
        }
    }

    /**
     * Populate created object.
     * <p>
     * AndroidAssembly2 added receiver parameter
     *
     * @param receiver the current {@link AndroidReceiver}
     * @param newCommand the current command
     * @param elementsMap the object's map
     * @param xreObject created object
     * @param params the copy of command parameters
     * @throws InvalidXRECommandParameterException if any command parameter has invalid value
     * @throws XREObjectNotFoundException if object is not found by given ID
     * @throws XREObjectCommandHandlerException if any other error occurred
     */
    private static void populate(AndroidReceiver receiver, XRENewCommand newCommand,
        Map<Integer, XREObject> elementsMap, XREObject xreObject, Map<String, Object> params)
        throws XREObjectCommandHandlerException {
        if (xreObject instanceof XRECommandSequence) {
            populateCommandSequence((XRECommandSequence) xreObject, params);
        } else if (xreObject instanceof XREView) {
            populateView((XREView) xreObject, params, elementsMap);
        } else if (xreObject instanceof XREText) {
            populateText((XREText) xreObject, params, elementsMap);
        } else if (xreObject instanceof XRETextInput) {
            populateTextInput((XRETextInput) xreObject, params, elementsMap);
        } else if (xreObject instanceof XREHTMLText) {
            populateHTMLText((XREHTMLText) xreObject, params, elementsMap);
        } else if (xreObject instanceof XREHTMLView) {
            populateHTMLView((XREHTMLView) xreObject, params);
        } else if (xreObject instanceof XREStylesheet) {
            populateStylesheet((XREStylesheet) xreObject, params);
        } else if (xreObject instanceof XRERectangle) {
            populateRectangle((XRERectangle) xreObject, params);
        } else if (xreObject instanceof XREFont) {
            populateFont((XREFont) xreObject, params);
        } else if (xreObject instanceof XRENineSliceImage) {
            populateNineSliceImage((XRENineSliceImage) xreObject, params, receiver);
        } else if (xreObject instanceof XREImage) {
            populateImage((XREImage) xreObject, params, receiver);
        } else if (xreObject instanceof XRESound) {
            populateSound(receiver, (XRESound) xreObject, params);
        } else if (xreObject instanceof XREVideo) {
            populateVideo((XREVideo) xreObject, params);
        } else if (xreObject instanceof XREFlash) {
            populateFlash((XREFlash) xreObject, params);
        } else if (xreObject instanceof XREApplication) {
            populateApplication((XREApplication) xreObject, params);
        } else if (xreObject instanceof XREAlphaAnimation) {
            populateAlphaAnimation((XREAlphaAnimation) xreObject, params);
        } else if (xreObject instanceof XREDimensionsAnimation) {
            populateDimensionsAnimation((XREDimensionsAnimation) xreObject, params);
        } else if (xreObject instanceof XREAbsoluteScaleAnimation) {
            populateAbsoluteScaleAnimation((XREAbsoluteScaleAnimation) xreObject, params);
        } else if (xreObject instanceof XRETransformAnimation) {
            populateTransformAnimation((XRETransformAnimation) xreObject, params);
        } else if (xreObject instanceof XREAbsoluteTranslationAnimation) {
            populateAbsoluteTranslationAnimation((XREAbsoluteTranslationAnimation) xreObject, params);
        } else if (xreObject instanceof XREAnimationResource) {
            populateAnimationResource((XREAnimationResource) xreObject, params);
        } else if (xreObject instanceof XREServiceProxy) {
        	populateServiceProxyResource((XREServiceProxy) xreObject, params);
        } else if (xreObject instanceof DoNothingSound) {
        	populateDoNothingSound(receiver, (DoNothingSound) xreObject, params);
        } else {
            throw new InvalidXRECommandParameterException("Passed klass '" + newCommand.getKlass()
                + "' is not supported.", "klass", newCommand.getKlass());
        }
    }

    /**
     * Populates {@link XRECommandSequence} object.
     *
     * @param xreObject the object to populate
     * @param params the command parameters
     * @throws InvalidXRECommandParameterException if any command parameter has invalid value
     */
    private static void populateCommandSequence(XRECommandSequence xreObject, Map<String, Object> params)
        throws InvalidXRECommandParameterException {
        List<?> commands = CommandHandlersUtil.getValue(params, "commands", List.class, true);

        CommandHandlersUtil.checkCollection(commands, XRECommand.class, "commands", commands, "commands");

        // set command index of each command
        for (Object command : commands) {
            ((XRECommand) command).setCommandIndex(XRECommand.LOCAL_COMMAND_INDEX);
        }
        xreObject.setCommands((List<XRECommand>) commands);
    }

    /**
     * Populates {@link XREView} object.
     *
     * @param xreObject the object to populate
     * @param params the command parameters
     * @param elementsMap the ApplicationData map of XREObjects
     * @throws XREObjectCommandHandlerException if XREView's parent do not have set children
     */
    @SuppressWarnings("boxing")
    private static void populateView(XREView xreObject, Map<String, Object> params, Map<Integer, XREObject> elementsMap)
        throws XREObjectCommandHandlerException {
        xreObject.setParent(CommandHandlersUtil.getById(params, "parent", elementsMap, XREView.class, xreObject
            .getParent()));
        xreObject.setName(CommandHandlersUtil.getString(params, "name", false, false, xreObject.getName()));
        xreObject.setAlpha(CommandHandlersUtil.getNum(params, "alpha", false, true, 1.0, xreObject.getAlpha()));
        int[] dimensions = CommandHandlersUtil.getDimensions(params, xreObject.getDimensions());
        dimensions[0] = CommandHandlersUtil.getNum(params, "width", false, true, -1, dimensions[0]);
        dimensions[1] = CommandHandlersUtil.getNum(params, "height", false, true, -1, dimensions[1]);
        xreObject.setDimensions(dimensions);
        xreObject.setMatrix(CommandHandlersUtil.getMatrix(params, xreObject.getMatrix()));
        xreObject.setResource(CommandHandlersUtil.getById(params, "resource", elementsMap, XREResource.class, xreObject
            .getResource()));
        xreObject.setResourceOptions(CommandHandlersUtil.getValue(params, "resourceOptions", XREResourceOptions.class,
            xreObject.getResourceOptions()));
        xreObject
            .setMask(CommandHandlersUtil.getById(params, "mask", elementsMap, XREImage.class, xreObject.getMask()));
        xreObject.setClip(CommandHandlersUtil.getBool(params, "clip", false, xreObject.isClip()));
        xreObject.setIgnoreMouse(CommandHandlersUtil.getBool(params, "ignoreMouse", false, xreObject.isIgnoreMouse()));
        xreObject.setVisible(CommandHandlersUtil.getBool(params, "visible", false, xreObject.isVisible()));
        xreObject.setPainting(CommandHandlersUtil.getBool(params, "painting", false, xreObject.isPainting()));
        xreObject.setPaintPropertyDisabled(CommandHandlersUtil.getBool(params, "paintPropertyDisabled", false, xreObject.isPaintPropertyDisabled()));
        if (xreObject.getParent() != null) {
            List<XREView> children = xreObject.getParent().getChildren();
            if (children == null) {
                throw new XREObjectCommandHandlerException("Parent of created XREView has null children.");
            }
            children.add(xreObject);
        }
    }

    /**
     * Populates {@link XREText} object.
     *
     * @param xreObject the object to populate
     * @param params the command parameters
     * @param elementsMap the ApplicationData map of XREObjects
     * @throws XREObjectNotFoundException if any XREObject to be associated is not found
     * @throws InvalidXRECommandParameterException if any command parameter has invalid value
     */
    @SuppressWarnings("boxing")
    private static void populateText(XREText xreObject, Map<String, Object> params, Map<Integer, XREObject> elementsMap)
        throws InvalidXRECommandParameterException, XREObjectNotFoundException {
        xreObject.setText(CommandHandlersUtil.getString(params, "text", false, true, xreObject.getText()));
        xreObject.setFont(CommandHandlersUtil.getById(params, "font", elementsMap, XREFont.class, xreObject.getFont()));
        xreObject.setSize(CommandHandlersUtil.getNum(params, "size", false, true, -1, xreObject.getSize()));
        xreObject.setColor(CommandHandlersUtil.getNum(params, "color", false, false, -1, xreObject.getColor()));
        xreObject.setBlinkingCursor(CommandHandlersUtil.getBool(params, "blinkingCursor", false, xreObject
            .isBlinkingCursor()));
        xreObject.setLeading(CommandHandlersUtil.getNum(params, "leading", false, false, -1, xreObject.getLeading()));
        xreObject.setDocumentMargin(CommandHandlersUtil.getNum(params, "documentMargin", false, true, -1.0, xreObject
            .getDocumentMargin()));
    }

    /**
     * Populates {@link XRETextInput} object.
     *
     * @param xreObject the object to populate
     * @param params the command parameters
     * @param elementsMap the ApplicationData map of XREObjects
     * @throws XREObjectNotFoundException if any XREObject to be associated is not found
     * @throws InvalidXRECommandParameterException if any command parameter has invalid value
     */
    @SuppressWarnings("boxing")
    private static void populateTextInput(XRETextInput xreObject, Map<String, Object> params,
        Map<Integer, XREObject> elementsMap) throws InvalidXRECommandParameterException, XREObjectNotFoundException {
        xreObject.setText(CommandHandlersUtil.getString(params, "text", false, true, ""));
        xreObject.setMaskText(CommandHandlersUtil.getBool(params, "maskText", false, false));
        xreObject.setFont(CommandHandlersUtil.getById(params, "font", elementsMap, XREFont.class, xreObject.getFont()));
        xreObject.setColor(CommandHandlersUtil.getNum(params, "color", false, false, -1, xreObject.getColor()));
        xreObject.setSize(CommandHandlersUtil.getNum(params, "size", false, true, -1, xreObject.getSize()));
    }

    /**
     * Populates {@link XREHTMLText} object.
     *
     * @param xreObject the object to populate
     * @param params the command parameters
     * @param elementsMap the ApplicationData map of XREObjects
     * @throws XREObjectNotFoundException if any XREObject to be associated is not found
     * @throws InvalidXRECommandParameterException if any command parameter has invalid value
     */
    @SuppressWarnings("boxing")
    private static void populateHTMLText(XREHTMLText xreObject, Map<String, Object> params,
        Map<Integer, XREObject> elementsMap) throws InvalidXRECommandParameterException, XREObjectNotFoundException {
        xreObject.setHtmlText(CommandHandlersUtil.getString(params, "htmlText", false, true, xreObject.getHtmlText()));
        xreObject.setStylesheet(CommandHandlersUtil.getById(params, "stylesheet", elementsMap, XREStylesheet.class,
            xreObject.getStylesheet()));
        xreObject.setLeading(CommandHandlersUtil.getNum(params, "leading", false, true, -1, xreObject.getLeading()));
    }

    /**
     * Populates {@link XREHTMLView} object.
     * <p>
     * AndroidAssembly3 new method
     *
     * @param xreObject the object to populate
     * @param params the command parameters
     * @throws InvalidXRECommandParameterException if any command parameter has invalid value
     */
    @SuppressWarnings("boxing")
    private static void populateHTMLView(XREHTMLView xreObject, Map<String, Object> params)
        throws InvalidXRECommandParameterException {
        xreObject.setUrl(CommandHandlersUtil.getString(params, "url", true, false, null));
        xreObject.setSpeed(CommandHandlersUtil.getNum(params, "speed", false, true, -1.0, xreObject.getSpeed()));
        xreObject.setPosition(CommandHandlersUtil.getNum(params, "position", false, true, -1, xreObject.getPosition()));
        xreObject.setContentType(CommandHandlersUtil.getString(params, "contentType", false, false, xreObject
            .getContentType()));
        xreObject.setNavigationMode(CommandHandlersUtil.getValue(params, "navigationMode", Object.class, xreObject
            .getNavigationMode()));
    }

    /**
     * Populates {@link XREStylesheet} object.
     *
     * @param xreObject the object to populate
     * @param params the command parameters
     * @throws InvalidXRECommandParameterException if any command parameter has invalid value
     */
    private static void populateStylesheet(XREStylesheet xreObject, Map<String, Object> params)
        throws InvalidXRECommandParameterException {
        xreObject.setCss(CommandHandlersUtil.getString(params, "css", true, false, null));
    }

    /**
     * Populates {@link XRERectangle} object.
     *
     * @param xreObject the object to populate
     * @param params the command parameters
     * @throws InvalidXRECommandParameterException if any command parameter has invalid value
     */
    @SuppressWarnings("boxing")
    private static void populateRectangle(XRERectangle xreObject, Map<String, Object> params)
        throws InvalidXRECommandParameterException {
        xreObject.setColor(CommandHandlersUtil.getNum(params, "color", false, false, -1, xreObject.getColor()));
        xreObject.setBorderColor(CommandHandlersUtil.getNum(params, "borderColor", false, false, -1, xreObject
            .getBorderColor()));
        xreObject.setBorderThickness(CommandHandlersUtil.getNum(params, "borderThickness", false, true, -1.0, xreObject
            .getBorderThickness()));
    }

    /**
     * Populates {@link XREFont} object.
     *
     * @param xreObject the object to populate
     * @param params the command parameters
     * @throws InvalidXRECommandParameterException if any command parameter has invalid value
     */
    private static void populateFont(XREFont xreObject, Map<String, Object> params)
        throws InvalidXRECommandParameterException {
        xreObject.setFamily(CommandHandlersUtil.getString(params, "family", false, false, xreObject.getFamily()));
        String style = CommandHandlersUtil.getString(params, "style", false, true, xreObject.getStyle());
        if (!FONT_STYLES.contains(style)) {
            throw new InvalidXRECommandParameterException(
                "Given value '" + style + "' of font style is not supported.", "style", style);
        }
        xreObject.setStyle(style);
    }

    /**
     * Populates {@link XREImage} object.
     *
     * @param xreObject the object to populate
     * @param params the command parameters
     * @throws InvalidXRECommandParameterException if any command parameter has invalid value
     */
    private static void populateImage(XREImage xreObject, Map<String, Object> params, AndroidReceiver receiver)
        throws InvalidXRECommandParameterException {
        xreObject.setUrl(CommandHandlersUtil.getString(params, "url", false, false, null));
        xreObject.setQuality(CommandHandlersUtil.getValue(params, "quality", XREImageQuality.class, xreObject
            .getQuality()));
        
        if (xreObject.getUrl() != null) {
        	try {
				PaintersUtil.loadImage(xreObject.getUrl(), receiver, xreObject);
			} catch (XREObjectPainterException e) {
				throw new InvalidXRECommandParameterException("image load failed", e, "url", xreObject.getUrl());
			}
        }
    }

    /**
     * Populates {@link XRENineSliceImage} object.
     *
     * @param xreObject the object to populate
     * @param params the command parameters
     * @throws InvalidXRECommandParameterException if any command parameter has invalid value
     */
    @SuppressWarnings("boxing")
    private static void populateNineSliceImage(XRENineSliceImage xreObject, Map<String, Object> params, AndroidReceiver receiver)
        throws InvalidXRECommandParameterException {
        populateImage(xreObject, params, receiver);

        xreObject.setLeft(CommandHandlersUtil.getNum(params, "left", false, true, -1, xreObject.getLeft()));
        xreObject.setRight(CommandHandlersUtil.getNum(params, "right", false, true, -1, xreObject.getRight()));
        xreObject.setTop(CommandHandlersUtil.getNum(params, "top", false, true, -1, xreObject.getTop()));
        xreObject.setBottom(CommandHandlersUtil.getNum(params, "bottom", false, true, -1, xreObject.getBottom()));
    }

    /**
     * Populates {@link XRESound} object.
     * <p>
     * AndroidAssembly2 added receiver parameter
     *
     * @param receiver the current {@link AndroidReceiver}
     * @param xreObject the object to populate
     * @param params the command parameters
     * @throws XREObjectCommandHandlerException if error occurs while populating and initializing XRESound
     */
    @SuppressWarnings("boxing")
    private static void populateSound(AndroidReceiver receiver, XRESound xreObject, Map<String, Object> params)
        throws XREObjectCommandHandlerException {
        xreObject.setUrl(CommandHandlersUtil.getString(params, "url", true, false, null));
        xreObject.setVolume(CommandHandlersUtil.getNum(params, "volume", false, true, CommandHandlersUtil.MAX_VOLUME,
            xreObject.getVolume()));
        xreObject.setPosition(CommandHandlersUtil.getNum(params, "position", false, true, -1, xreObject.getPosition()));
        xreObject.setSpeed(CommandHandlersUtil.getNum(params, "speed", false, false, -1.0, xreObject.getSpeed()));
        xreObject.setAutoPlay(CommandHandlersUtil.getBool(params, "autoPlay", false, xreObject.isAutoPlay()));
        xreObject.setContentType(CommandHandlersUtil.getString(params, "contentType", false, false, xreObject
            .getContentType()));

        try {
            // AndroidAssembly2 added special case for XRESound that is not attached to XREView
            // init created sound
            XRESoundUtil.init(receiver, xreObject);
        } catch (XREObjectPainterException e) {
            throw new XREObjectCommandHandlerException("Error occurred while initializing XRESound '"
                + xreObject.getId() + "', URL '" + xreObject.getUrl() + "'.", e);
        }
    }

    private static void populateDoNothingSound(AndroidReceiver receiver, DoNothingSound xreObject, Map<String, Object> params)
	    throws XREObjectCommandHandlerException {
	 /*   xreObject.setUrl(CommandHandlersUtil.getString(params, "url", true, false, null));
	    xreObject.setVolume(CommandHandlersUtil.getNum(params, "volume", false, true, CommandHandlersUtil.MAX_VOLUME,
	        xreObject.getVolume()));
	    xreObject.setPosition(CommandHandlersUtil.getNum(params, "position", false, true, -1, xreObject.getPosition()));
	    xreObject.setSpeed(CommandHandlersUtil.getNum(params, "speed", false, false, -1.0, xreObject.getSpeed()));
	    xreObject.setAutoPlay(CommandHandlersUtil.getBool(params, "autoPlay", false, xreObject.isAutoPlay()));
	    xreObject.setContentType(CommandHandlersUtil.getString(params, "contentType", false, false, xreObject
	        .getContentType()));
*/
	}
    
    /**
     * Populates {@link XREFlash} object.
     *
     * @param xreObject the object to populate
     * @param params the command parameters
     * @throws InvalidXRECommandParameterException if any command parameter has invalid value
     */
    private static void populateFlash(XREFlash xreObject, Map<String, Object> params)
        throws InvalidXRECommandParameterException {
        xreObject.setUrl(CommandHandlersUtil.getString(params, "url", true, false, null));
        Map<?, ?> flashVars = CommandHandlersUtil.getValue(params, "flashVars", Map.class, false);
        if (flashVars != null) {
            // check collection
            CommandHandlersUtil.checkCollection(flashVars.keySet(), String.class, "flashVars", flashVars,
                "flashVars.keys");
            xreObject.setFlashVars((Map<String, Object>) flashVars);
        }
    }

    /**
     * Populates {@link XREVideo} object.
     *
     * @param xreObject the object to populate
     * @param params the command parameters
     * @throws InvalidXRECommandParameterException if any command parameter has invalid value
     */
    @SuppressWarnings("boxing")
    private static void populateVideo(XREVideo xreObject, Map<String, Object> params)
        throws InvalidXRECommandParameterException {
        xreObject.setUrl(CommandHandlersUtil.getString(params, "url", true, false, null));
        xreObject.setVolume(CommandHandlersUtil.getNum(params, "volume", false, true, CommandHandlersUtil.MAX_VOLUME,
            xreObject.getVolume()));
        xreObject.setSpeed(CommandHandlersUtil.getNum(params, "speed", false, false, -1.0, xreObject.getSpeed()));
        xreObject.setAutoPlay(CommandHandlersUtil.getBool(params, "autoPlay", false, true));
        xreObject.setContentType(CommandHandlersUtil.getString(params, "contentType", false, false, xreObject
            .getContentType()));
        xreObject.setPosition(CommandHandlersUtil.getNum(params, "position", false, true, -1, xreObject.getPosition()));

        // AndroidAssembly3 added support for contentOptions
        // get and check content options
        List<?> contentOptions = CommandHandlersUtil.getValue(params, "contentOptions", List.class, true);
        CommandHandlersUtil.checkCollection(contentOptions, Map.class, "contentOptions", contentOptions,
            "contentOptions.items");
        xreObject.setContentOptions((List<Map<String, String>>) contentOptions);
    }

    /**
     * Populates {@link XREApplication} object.
     *
     * @param xreObject the object to populate
     * @param params the command parameters
     * @throws InvalidXRECommandParameterException if any command parameter has invalid value
     */
    private static void populateApplication(XREApplication xreObject, Map<String, Object> params)
        throws InvalidXRECommandParameterException {
        xreObject.setUrl(CommandHandlersUtil.getString(params, "url", true, false, null));
        xreObject.setMinimumVersion(CommandHandlersUtil.getString(params, "minimumVersion", false, false, xreObject
            .getMinimumVersion()));
        Map<?, ?> launchParams = CommandHandlersUtil.getValue(params, "launchParams", Map.class, false);
        if (launchParams != null) {
            // check collection
            CommandHandlersUtil.checkCollection(launchParams.keySet(), String.class, "launchParams", launchParams,
                "launchParams.keys");
            xreObject.setLaunchParams((Map<String, Object>) launchParams);
        }
        xreObject.setSessionGUID(CommandHandlersUtil.getString(params, "sessionGUID", false, false, xreObject
            .getSessionGUID()));
    }

    /**
     * Populates {@link XREAnimationResource} object.
     *
     * @param xreObject the object to populate
     * @param params the command parameters
     * @throws InvalidXRECommandParameterException if any command parameter has invalid value
     */
    @SuppressWarnings("boxing")
    private static void populateAnimationResource(XREAnimationResource xreObject, Map<String, Object> params)
        throws InvalidXRECommandParameterException {
        xreObject.setDuration(CommandHandlersUtil.getNum(params, "duration", true, true, -1, 0));
        xreObject.setEasing(CommandHandlersUtil.getValue(params, "easing", XREAnimationEasingFunction.class, xreObject
            .getEasing()));
    }

    /**
     * Populates {@link XREAlphaAnimation} object.
     *
     * @param xreObject the object to populate
     * @param params the command parameters
     * @throws InvalidXRECommandParameterException if any command parameter has invalid value
     */
    @SuppressWarnings("boxing")
    private static void populateAlphaAnimation(XREAlphaAnimation xreObject, Map<String, Object> params)
        throws InvalidXRECommandParameterException {
        populateAnimationResource(xreObject, params);

        xreObject.setAlpha(CommandHandlersUtil.getNum(params, "alpha", true, true, 1.0, 0.0));
    }

    /**
     * Populates {@link XREDimensionsAnimation} object.
     *
     * @param xreObject the object to populate
     * @param params the command parameters
     * @throws InvalidXRECommandParameterException if any command parameter has invalid value
     */
    @SuppressWarnings("boxing")
    private static void populateDimensionsAnimation(XREDimensionsAnimation xreObject, Map<String, Object> params)
        throws InvalidXRECommandParameterException {
        populateAnimationResource(xreObject, params);

        xreObject.setWidth(CommandHandlersUtil.getNum(params, "width", true, true, -1, 0));
        xreObject.setHeight(CommandHandlersUtil.getNum(params, "height", true, true, -1, 0));
    }

    /**
     * Populates {@link XREAbsoluteScaleAnimation} object.
     *
     * @param xreObject the object to populate
     * @param params the command parameters
     * @throws InvalidXRECommandParameterException if any command parameter has invalid value
     */
    @SuppressWarnings("boxing")
    private static void populateAbsoluteScaleAnimation(XREAbsoluteScaleAnimation xreObject, Map<String, Object> params)
        throws InvalidXRECommandParameterException {
        populateAnimationResource(xreObject, params);

        xreObject.setSx(CommandHandlersUtil.getNum(params, "sx", true, true, -1, 0));
        xreObject.setSy(CommandHandlersUtil.getNum(params, "sy", true, true, -1, 0));
    }

    /**
     * Populates {@link XREServiceProxy} object.
     *
     * @param xreObject the object to populate
     * @param params the command parameters
     * @throws InvalidXRECommandParameterException if any command parameter has invalid value
     */
    @SuppressWarnings("boxing")
    private static void populateServiceProxyResource(XREServiceProxy xreObject, Map<String, Object> params)
        throws InvalidXRECommandParameterException {
    	
    }
    
    /**
     * Populates {@link XREAbsoluteTranslationAnimation} object.
     * <p>
     * AndroidAssembly3 new method, added to support {@link XREAbsoluteTranslationAnimation}
     *
     * @param xreObject the object to populate
     * @param params the command parameters
     * @throws InvalidXRECommandParameterException if any command parameter has invalid value
     */
    @SuppressWarnings("boxing")
    private static void populateAbsoluteTranslationAnimation(XREAbsoluteTranslationAnimation xreObject,
        Map<String, Object> params) throws InvalidXRECommandParameterException {
        populateAnimationResource(xreObject, params);

        xreObject.setX(CommandHandlersUtil.getNum(params, "x", true, false, -1, 0));
        xreObject.setY(CommandHandlersUtil.getNum(params, "y", true, false, -1, 0));
    }

    /**
     * Populates {@link XRETransformAnimation} object.
     *
     * @param xreObject the object to populate
     * @param params the command parameters
     * @throws InvalidXRECommandParameterException if any command parameter has invalid value
     */
    @SuppressWarnings("boxing")
    private static void populateTransformAnimation(XRETransformAnimation xreObject, Map<String, Object> params)
        throws InvalidXRECommandParameterException {
        populateAnimationResource(xreObject, params);

        xreObject.setX(CommandHandlersUtil.getNum(params, "x", false, false, 0, xreObject.getX()));
        xreObject.setY(CommandHandlersUtil.getNum(params, "y", false, false, 0, xreObject.getY()));
        xreObject.setScaleX(CommandHandlersUtil.getNum(params, "scaleX", false, true, -1.0, xreObject.getScaleX()));
        xreObject.setScaleY(CommandHandlersUtil.getNum(params, "scaleY", false, true, -1.0, xreObject.getScaleY()));
        xreObject.setRotation(CommandHandlersUtil.getNum(params, "rotation", false, false, -1.0, xreObject
            .getRotation()));
        xreObject.setActionPointX(CommandHandlersUtil.getNum(params, "actionPointX", false, true, -1, xreObject
            .getActionPointX()));
        xreObject.setActionPointY(CommandHandlersUtil.getNum(params, "actionPointY", false, true, -1, xreObject
            .getActionPointY()));
    }

    /**
     * Creates subclass of {@link XREObject} class.
     *
     * @param className the name of subclass
     * @return the created subclass {@link XREObject}
     * @throws XREObjectCreationException if any error occurred during creation of object
     * @throws InvalidXRECommandParameterException if klass property is null
     */
    private static XREObject createObject(String className) throws XREObjectCreationException,
        InvalidXRECommandParameterException {
        if (className == null) {
            throw new InvalidXRECommandParameterException("Klass property is null.", "klass", null);
        }
        try {
            // AndroidAssembly1 added support of simple names
            Class<?> clazz;
            try {
                // get class for given name
                clazz = Class.forName(className);
            } catch (ClassNotFoundException e) {
                clazz = Class.forName("com.hercules.android.receiver.model.objects." + className);
            }

            // get parameter-less constructor
            Constructor<?> ctor = clazz.getConstructor();

            // create instance and check if it is correct
            Object instance = ctor.newInstance();
            if (instance instanceof XREObject) {
                return (XREObject) instance;
            }
            throw new XREObjectCreationException("Class '" + className + "' is not subclass of '"
                + XREObject.class.getName() + "'.", className);
        } catch (ClassNotFoundException e) {
            throw new XREObjectCreationException("The '" + className + "' class is not found.", e, className);
        } catch (NoSuchMethodException e) {
            throw new XREObjectCreationException("The '" + className + "' do not have required constructor.", e,
                className);
        } catch (SecurityException e) {
            throw new XREObjectCreationException("Security error occurs while getting "
                + "required constructor of the class '" + className + "'.", e, className);
        } catch (InstantiationException e) {
            throw new XREObjectCreationException("The '" + className + "' is an abstract class.", e, className);
        } catch (IllegalAccessException e) {
            throw new XREObjectCreationException("The required constructor of '" + className + "' is inaccessible.", e,
                className);
        } catch (InvocationTargetException e) {
            throw new XREObjectCreationException("An exception was thrown by the invoked constructor of the class '"
                + className + "'.", e, className);
        } catch (ExceptionInInitializerError e) {
            throw new XREObjectCreationException("Failed to initialize class '" + className + "'.", e, className);
        } catch (LinkageError e) {
            throw new XREObjectCreationException("Linkage failed for class '" + className + "'.", e, className);
        }
    }
}